package com.eight.cloud.mybatisplus.handler;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler;
import com.eight.cloud.core.global.model.DataScopeModel;
import com.eight.cloud.core.global.model.BaseUser;
import com.eight.cloud.core.global.model.LoginUser;
import com.eight.cloud.core.utils.HttpUtils.HttpRequestUtils;
import com.eight.cloud.core.utils.supply.UserContext;
import com.eight.cloud.mybatisplus.datascope.SqlWhereExpression;
import com.eight.cloud.mybatisplus.datascope.annotation.DataColumn;
import com.eight.cloud.mybatisplus.datascope.annotation.DataScope;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.schema.Table;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import static com.eight.cloud.core.global.constant.NumConstant.ONE;
import static com.eight.cloud.core.global.constant.NumConstant.ZERO;
import static com.eight.cloud.core.global.constant.StrConstant.DOT;

/**
 * mybatis-plus数据权限处理器
 *
 * @ClassName: DataPermissionHandler
 * @Author: TXC
 * @Date: 2024-10-05 22:23
 **/
@Slf4j
public class MpDataPermissionHandler implements MultiDataPermissionHandler {
    private static final String _COUNT = "_mpCount";

    private final String module;

    public MpDataPermissionHandler(String module) {
        this.module = module;
    }

    /**
     * 获取数据权限 SQL 片段。
     *
     * @param table             所执行的数据库表信息，可以通过此参数获取表名和表别名
     * @param where             原有的 where 条件信息
     * @param mappedStatementId Mybatis MappedStatement id 根据该参数可以判断具体执行方法:方法全路径
     * @return JSqlParser 条件表达式，返回的条件表达式会拼接在原有的表达式后面（不会覆盖原有的表达式）
     */
    @Override
    public Expression getSqlSegment(Table table, Expression where, String mappedStatementId) {
        try {
            Class<?> mapperClazz = Class.forName(mappedStatementId.substring(0, mappedStatementId.lastIndexOf(DOT)));
            String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(DOT) + ONE);
            // 获取 DataScope注解 DataScope注解优先级：【方法上 > 类上】
            // 获取自身类中的所有方法，不包括继承。与访问权限无关
            Method[] methods = mapperClazz.getDeclaredMethods();
            for (Method method : methods) {
                DataScope dataScopeAnnotationMethod = method.getAnnotation(DataScope.class);
                if (ObjectUtils.isEmpty(dataScopeAnnotationMethod) || dataScopeAnnotationMethod.ignore()) {
                    continue;
                }
                if (method.getName().equals(methodName) || (method.getName() + _COUNT).equalsIgnoreCase(methodName)) {
                    return buildDataScopeByAnnotation(dataScopeAnnotationMethod);
                }
            }
            DataScope dataScopeAnnotationClazz = mapperClazz.getAnnotation(DataScope.class);
            if (ObjectUtils.isNotEmpty(dataScopeAnnotationClazz) && !dataScopeAnnotationClazz.ignore()) {
                return buildDataScopeByAnnotation(dataScopeAnnotationClazz);
            }
        } catch (ClassNotFoundException e) {
            log.error("【DataScopeHandlerPlus】获取数据权限失败，请检查是否配置了DataScope注解！", e);
        }
        return null;
    }


    /**
     * DataScope注解方式，拼装数据权限
     *
     * @param controllerDataScope 数据权限注解
     * @return 表达式
     */
    private Expression buildDataScopeByAnnotation(DataScope controllerDataScope) {
        // 获取当前的用户
        LoginUser currentUser = UserContext.getUser();
        if (ObjectUtil.isNotNull(currentUser)) {
            DataScopeModel dataScopeModel = getUserDataScope(currentUser);
            DataColumn[] dataColumns = controllerDataScope.columns();
            List<Expression> expressions = new ArrayList<>();
            for (DataColumn dataColumn : dataColumns) { // 遍历数据权限字段
                SqlWhereExpression sqlWhereExpression = dataColumn.dataScopeType().getSqlWhereExpression();
                Expression expression = sqlWhereExpression.getExpression(dataColumn.alias(), dataColumn.column(),
                        currentUser, dataScopeModel);
                if (ObjectUtil.isNotNull(expression)) {
                    expressions.add(expression);
                }
            }
            return dataScopeFilter(expressions, null);
        }
        return null;
    }

    /**
     * 获取用户数据权限列表
     *
     * @param currentUser 用户信息
     * @return 数据权限列表
     */
    private DataScopeModel getUserDataScope(LoginUser currentUser) {
        String permissionsCode = HttpRequestUtils.getPermissionsCode(module);
        if (ObjectUtil.isNotNull(currentUser)) {
            return currentUser.obtainRoleDataScope(permissionsCode);
        }
        return null;
    }


    /**
     * 拼装数据权限
     *
     * @param expressions 表达式列表
     * @return 表达式
     */
    private Expression dataScopeFilter(List<Expression> expressions, Expression expression) {
        if (CollectionUtils.isEmpty(expressions)) {
            return expression;
        }
        Expression rightValue = expressions.get(ZERO);
        expressions.remove(ZERO);
        return dataScopeFilter(expressions,
                ObjectUtil.isEmpty(expression) ? rightValue : new OrExpression(expression, rightValue));
    }
}
